package gui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.DefaultComboBoxModel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSpinner;
import javax.swing.JTextPane;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.SpinnerNumberModel;
import javax.swing.UIManager;

import org.scilab.forge.jlatexmath.TeXIcon;

import brac.Bisection;
import brac.Bracketing;
import brac.FalsePosition;
import brac.FixedPoint;
import brac.NewtonRaphson;
import brac.Secant;
import fn.Function;
import fn.Latex;

public class BraketingPanel extends JPanel {
	private static final long serialVersionUID = -940402774745397057L;

	public JLabel lblFx;
	public JTextPane txtpnFunction;
	public JScrollPane scrollPane;
	public JPanel panel;
	public JLabel lblParameters;
	private JLabel lblPrecision;
	private JSpinner spnPrecision;
	private JLabel lblX;
	private JSpinner spnA;
	private JLabel lblX_1;
	private JSpinner spnB;
	private JLabel lblFunction;
	private JSeparator separator_2;
	public JSeparator separator;
	private JComboBox<Bracketing> comboBox;
	private JSpinner spnIterations;
	private PlotPanel plot;
	private Function fn;

	public static void main(String[] args) throws Exception {
		UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		JFrame f = new JFrame();
		f.setVisible(true);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		BraketingPanel p = new BraketingPanel(null);
		f.getContentPane().add(p);
		f.pack();
	}

	public BraketingPanel(PlotPanel plot) {
		this.plot = plot;
		init();
	}

	private void init() {
		setPreferredSize(new Dimension(256, 256));
		setFocusable(false);
		setFocusTraversalKeysEnabled(false);
		lblFx = new JLabel("") {
			private static final long serialVersionUID = 2780638449319426443L;

			@Override
			public void paint(Graphics arg0) {
				Latex.draw("f(x) = ", 16, this, arg0, getForeground());
			}

		};
		lblFx.setFocusable(false);
		lblFx.setFocusTraversalKeysEnabled(false);

		txtpnFunction = new JTextPane();
		txtpnFunction.setFocusTraversalKeysEnabled(false);
		txtpnFunction.setBorder(UIManager.getBorder("ScrollPane.border"));
		txtpnFunction.addKeyListener(new KeyAdapter() {
			@Override
			public void keyReleased(KeyEvent arg0) {
				super.keyTyped(arg0);
				do_txtpnFunction_keyTyped(arg0);
			}
		});
		txtpnFunction.setText("x * sin(x)");

		scrollPane = new JScrollPane();
		scrollPane.setFocusable(false);
		scrollPane.setFocusTraversalKeysEnabled(false);

		lblParameters = new JLabel("Parameters");

		JLabel lblIterations = new JLabel() {
			private static final long serialVersionUID = 3250726115284265528L;

			@Override
			public void paint(Graphics arg0) {
				arg0.translate(0, 6);
				Latex.draw("n = ", 16, this, arg0, getForeground());
			}
		};

		spnIterations = new JSpinner();
		spnIterations.setModel(new SpinnerNumberModel(50, 1, 1000, 1));

		lblPrecision = new JLabel() {
			private static final long serialVersionUID = 5711719501853854729L;

			@Override
			public void paint(Graphics arg0) {
				arg0.translate(4, 0);
				Latex.draw("\\epsilon = 10^{-}", 16, this, arg0, getForeground());
			}
		};

		spnPrecision = new JSpinner();
		spnPrecision.setModel(new SpinnerNumberModel(5, -5, 20, 1));

		lblX = new JLabel() {
			private static final long serialVersionUID = 816131776697311536L;

			@Override
			public void paint(Graphics arg0) {
				arg0.translate(0, 6);
				Latex.draw("x_0 = ", 16, this, arg0, getForeground());
			}
		};

		spnA = new JSpinner();
		spnA.setModel(new SpinnerNumberModel(new Double(0), null, null, new Double(1)));

		lblX_1 = new JLabel() {
			private static final long serialVersionUID = -3634841419246743362L;

			@Override
			public void paint(Graphics arg0) {
				arg0.translate(4, 6);
				Latex.draw("x_1 = ", 16, this, arg0, getForeground());
			}
		};

		spnB = new JSpinner();
		spnB.setModel(new SpinnerNumberModel(new Double(1), null, null, new Double(1)));

		JLabel lblMethod = new JLabel("Method");

		JSeparator separator_1 = new JSeparator();

		comboBox = new JComboBox<Bracketing>();
		comboBox.setModel(new DefaultComboBoxModel<Bracketing>(
				new Bracketing[] { new FixedPoint(), new Bisection(), new FalsePosition(), new NewtonRaphson(), new Secant() }));

		lblFunction = new JLabel("Function");

		separator_2 = new JSeparator();

		separator = new JSeparator();
		GroupLayout groupLayout = new GroupLayout(this);
		groupLayout.setHorizontalGroup(groupLayout.createParallelGroup(Alignment.LEADING).addGroup(
				groupLayout
						.createSequentialGroup()
						.addContainerGap()
						.addGroup(
								groupLayout
										.createParallelGroup(Alignment.LEADING)
										.addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 239, Short.MAX_VALUE)
										.addGroup(
												groupLayout.createSequentialGroup().addComponent(lblMethod, GroupLayout.PREFERRED_SIZE, 59, GroupLayout.PREFERRED_SIZE)
														.addPreferredGap(ComponentPlacement.UNRELATED)
														.addComponent(separator_1, GroupLayout.PREFERRED_SIZE, 166, GroupLayout.PREFERRED_SIZE))
										.addGroup(
												groupLayout.createSequentialGroup().addComponent(lblFunction, GroupLayout.PREFERRED_SIZE, 59, GroupLayout.PREFERRED_SIZE)
														.addPreferredGap(ComponentPlacement.UNRELATED)
														.addComponent(separator_2, GroupLayout.PREFERRED_SIZE, 166, GroupLayout.PREFERRED_SIZE))
										.addGroup(
												groupLayout.createSequentialGroup().addComponent(lblFx, GroupLayout.PREFERRED_SIZE, 39, GroupLayout.PREFERRED_SIZE)
														.addPreferredGap(ComponentPlacement.RELATED)
														.addComponent(txtpnFunction, GroupLayout.DEFAULT_SIZE, 195, Short.MAX_VALUE))
										.addComponent(comboBox, GroupLayout.PREFERRED_SIZE, 215, GroupLayout.PREFERRED_SIZE)
										.addGroup(
												groupLayout.createSequentialGroup().addComponent(lblParameters)
														.addPreferredGap(ComponentPlacement.RELATED, 14, Short.MAX_VALUE)
														.addComponent(separator, GroupLayout.PREFERRED_SIZE, 166, GroupLayout.PREFERRED_SIZE))
										.addGroup(
												groupLayout
														.createSequentialGroup()
														.addGroup(
																groupLayout.createParallelGroup(Alignment.LEADING, false)
																		.addComponent(lblX, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
																		.addComponent(lblIterations, GroupLayout.DEFAULT_SIZE, 61, Short.MAX_VALUE))
														.addGap(4)
														.addGroup(
																groupLayout.createParallelGroup(Alignment.TRAILING)
																		.addComponent(spnIterations, GroupLayout.PREFERRED_SIZE, 51, Short.MAX_VALUE)
																		.addComponent(spnA, Alignment.LEADING, GroupLayout.PREFERRED_SIZE, 50, GroupLayout.PREFERRED_SIZE))
														.addPreferredGap(ComponentPlacement.UNRELATED)
														.addGroup(
																groupLayout.createParallelGroup(Alignment.LEADING, false)
																		.addComponent(lblX_1, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
																		.addComponent(lblPrecision, GroupLayout.DEFAULT_SIZE, 59, Short.MAX_VALUE))
														.addPreferredGap(ComponentPlacement.RELATED)
														.addGroup(
																groupLayout.createParallelGroup(Alignment.LEADING, false)
																		.addComponent(spnB, GroupLayout.PREFERRED_SIZE, 47, GroupLayout.PREFERRED_SIZE)
																		.addComponent(spnPrecision, GroupLayout.PREFERRED_SIZE, 47, GroupLayout.PREFERRED_SIZE))))
						.addContainerGap()));
		groupLayout.setVerticalGroup(groupLayout.createParallelGroup(Alignment.LEADING).addGroup(
				groupLayout
						.createSequentialGroup()
						.addContainerGap()
						.addGroup(
								groupLayout.createParallelGroup(Alignment.TRAILING).addComponent(lblMethod, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE)
										.addComponent(separator_1, GroupLayout.PREFERRED_SIZE, 4, GroupLayout.PREFERRED_SIZE))
						.addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(comboBox, GroupLayout.PREFERRED_SIZE, 23, GroupLayout.PREFERRED_SIZE)
						.addPreferredGap(ComponentPlacement.RELATED)
						.addGroup(
								groupLayout.createParallelGroup(Alignment.TRAILING).addComponent(lblFunction, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE)
										.addComponent(separator_2, GroupLayout.PREFERRED_SIZE, 4, GroupLayout.PREFERRED_SIZE))
						.addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(scrollPane, GroupLayout.PREFERRED_SIZE, 50, GroupLayout.PREFERRED_SIZE)
						.addPreferredGap(ComponentPlacement.RELATED)
						.addGroup(
								groupLayout.createParallelGroup(Alignment.TRAILING, false)
										.addComponent(lblFx, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
										.addComponent(txtpnFunction, GroupLayout.DEFAULT_SIZE, 40, Short.MAX_VALUE))
						.addPreferredGap(ComponentPlacement.RELATED)
						.addGroup(
								groupLayout.createParallelGroup(Alignment.TRAILING).addComponent(lblParameters)
										.addComponent(separator, GroupLayout.PREFERRED_SIZE, 4, GroupLayout.PREFERRED_SIZE))
						.addPreferredGap(ComponentPlacement.RELATED)
						.addGroup(
								groupLayout.createParallelGroup(Alignment.LEADING, false)
										.addComponent(spnIterations, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
										.addComponent(lblPrecision, GroupLayout.PREFERRED_SIZE, 19, GroupLayout.PREFERRED_SIZE)
										.addComponent(spnPrecision, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
										.addComponent(lblIterations, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
						.addPreferredGap(ComponentPlacement.RELATED)
						.addGroup(
								groupLayout.createParallelGroup(Alignment.LEADING).addComponent(lblX_1, GroupLayout.PREFERRED_SIZE, 19, GroupLayout.PREFERRED_SIZE)
										.addComponent(spnB, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
										.addComponent(lblX, GroupLayout.PREFERRED_SIZE, 20, GroupLayout.PREFERRED_SIZE)
										.addComponent(spnA, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
						.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)));

		panel = new JPanel() {

			/**
			 * 
			 */
			private static final long serialVersionUID = -1112304401439463594L;

			@Override
			public void paint(Graphics arg0) {
				super.paint(arg0);
				try {
					TeXIcon ti;
					try {
						ti = Latex.create(fn.toLatex(), 16);
						ti.setForeground(Color.BLACK);
					} catch (Exception e) {
						ti = Latex.create("incomplete", 16);
						ti.setForeground(Color.RED.darker());
					}
					ti.paintIcon(this, arg0, 4, 4);
					if (ti.getIconWidth() != getWidth() && ti.getIconHeight() != getHeight()) {
						setSize(ti.getIconWidth(), ti.getIconHeight());
						setPreferredSize(getSize());
					}
				} catch (Exception e) {}
			}
		};
		panel.setSize(10, 10);
		panel.setPreferredSize(getSize());
		scrollPane.setViewportView(panel);
		panel.setAlignmentY(Component.TOP_ALIGNMENT);
		panel.setAlignmentX(Component.LEFT_ALIGNMENT);
		panel.setFocusable(false);
		panel.setFocusTraversalKeysEnabled(false);
		panel.setBackground(Color.WHITE);
		GroupLayout gl_panel = new GroupLayout(panel);
		gl_panel.setHorizontalGroup(gl_panel.createParallelGroup(Alignment.LEADING).addGap(0, 254, Short.MAX_VALUE));
		gl_panel.setVerticalGroup(gl_panel.createParallelGroup(Alignment.LEADING).addGap(0, 81, Short.MAX_VALUE));
		panel.setLayout(gl_panel);
		setLayout(groupLayout);
		do_txtpnFunction_keyTyped(null);
	}

	protected void do_txtpnFunction_keyTyped(KeyEvent arg0) {
		try {
			fn = Function.parse(txtpnFunction.getText());
			panel.repaint();
			if (plot != null) {
				plot.removeFnAll();
				plot.addFn(fn);
			}
		} catch (Exception e) {}
	}

	public Bracketing solve() {
		Bracketing out = (Bracketing) comboBox.getSelectedItem();
		int itr = (Integer) spnIterations.getValue();
		double prec = Math.pow(10, -(Integer) spnPrecision.getValue());
		double a = (Double) spnA.getValue();
		double b = (Double) spnB.getValue();
		out.solveAndInit(Function.parse(txtpnFunction.getText()), prec, itr, a, b);
		return out;
	}

	public Function getFn() {
		return Function.parse(txtpnFunction.getText());
	}
}
